package com.msh.artascope.devcloud.service.service.impl;


import com.alibaba.fastjson.JSON;
import com.msh.artascope.devcloud.client.enums.biz.JenkinsBuildResultEnum;
import com.msh.artascope.devcloud.client.po.EnvPo;
import com.msh.artascope.devcloud.client.po.GitlabConfigPo;
import com.msh.artascope.devcloud.client.po.JenkinsConfigPo;
import com.msh.artascope.devcloud.client.po.ModuleBuildPo;
import com.msh.artascope.devcloud.client.po.ModulePo;
import com.msh.artascope.devcloud.client.po.ModuleResourcePo;
import com.msh.artascope.devcloud.client.po.ProjectPo;
import com.msh.artascope.devcloud.client.po.RegisterConfigPo;
import com.msh.artascope.devcloud.client.qo.ModuleBuildQo;
import com.msh.artascope.devcloud.client.qo.ModuleResourceQo;
import com.msh.artascope.devcloud.service.dao.ModuleBuildDao;
import com.msh.artascope.devcloud.service.model.query.ModuleBuildQueryVo;
import com.msh.artascope.devcloud.service.model.vo.BuildLogVo;
import com.msh.artascope.devcloud.service.model.vo.ModuleBuildVo;
import com.msh.artascope.devcloud.service.service.EnvService;
import com.msh.artascope.devcloud.service.service.GitlabConfigService;
import com.msh.artascope.devcloud.service.service.JenkinsConfigService;
import com.msh.artascope.devcloud.service.service.ModuleBuildService;
import com.msh.artascope.devcloud.service.service.ModuleResourceService;
import com.msh.artascope.devcloud.service.service.ModuleService;
import com.msh.artascope.devcloud.service.service.ProjectService;
import com.msh.artascope.devcloud.service.service.RegisterConfigService;
import com.msh.artascope.devcloud.service.wrapper.GitWrapper;
import com.msh.artascope.devcloud.service.wrapper.JenkinsWrapper;
import com.msh.frame.client.base.TenantBaseServiceImpl;
import com.msh.frame.client.common.Result;
import com.msh.frame.client.enums.YesNoEnum;
import com.msh.frame.client.exception.BizException;
import com.msh.frame.interfaces.IdGenerateable;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

/**
 * @author shihu
 * @mail m-sh@qq.com
 */
@Service
@Slf4j
public class ModuleBuildServiceImpl extends TenantBaseServiceImpl<ModuleBuildPo,ModuleBuildQo> implements ModuleBuildService {

  @Resource
  private ModuleBuildDao moduleBuildDao;

  @Resource
  private IdGenerateable idGenerateable;

  @Autowired
  private JenkinsWrapper jenkinsWrapper;

  @Autowired
  private ModuleService moduleService;

  @Autowired
  private ModuleResourceService moduleResourceService;

  @Autowired
  private ProjectService projectService;

  @Autowired
  private GitlabConfigService gitlabConfigService;

  @Autowired
  private JenkinsConfigService jenkinsConfigService;

  @Autowired
  private RegisterConfigService registerConfigService;

  @Autowired
  private GitWrapper gitWrapper;

  @Autowired
  private EnvService envService;

  @Override
  public long insert(ModuleBuildPo param) {
    if(null == param.getId()){
      param.setId(idGenerateable.getUniqueId());
    }
    return super.insert(param);
  }

  @Override
  public int insertCollection(Collection<ModuleBuildPo> param) {
    if(CollectionUtils.isEmpty(param)){
      return 0;
    }
    Long[] uniqueIds = idGenerateable.getUniqueIds(param.size());
    int i=0;
    for (ModuleBuildPo po : param) {
      if(null == po.getId()){
        po.setId(uniqueIds[i++]);
      }
    }
    return super.insertCollection(param);
  }

  @Override
  public void clearBuildNum(ModuleBuildQo moduleBuildQo) {
    moduleBuildDao.deleteBuildNum(moduleBuildQo);
  }

  @Override
  public void updateRunning(Long id, Integer runningFlag, Integer updateVersion, Long tenantId) {
    ModuleBuildPo po = new ModuleBuildPo();
    po.setId(id);
    po.setRunningFlag(runningFlag);
    po.setUpdateVersion(updateVersion);
    po.setTenantId(tenantId);
    update(po);
  }

  @Override
  public void updateRunning(Long id, Integer runningFlag, Long tenantId) {
    ModuleBuildPo moduleBuildPo = get(id, tenantId);
    if (null == moduleBuildPo) {
      return;
    }
    moduleBuildPo.setRunningFlag(runningFlag);
    update(moduleBuildPo);
  }

  @Override
  public void clearRunning(Long moduleId, Long tenantId, Long excludeModuleBuildingId) {
    List<ModuleBuildPo> list = list(new ModuleBuildQo().setModuleId(moduleId).setTenantId(tenantId)
        .setRunningFlag(YesNoEnum.YES.getValue()));
    if (!CollectionUtils.isEmpty(list)) {
      list.forEach(po -> {
        if (!po.getId().equals(excludeModuleBuildingId)) {
          updateRunning(po.getId(), YesNoEnum.NO.getValue(), po.getUpdateVersion(), tenantId);
        }
      });
    }
  }

  // ----------前端vo处理-------------------------------------------------------

  @Override
  public ModuleBuildVo build(ModuleBuildVo moduleBuildVo) {
    Long moduleId = moduleBuildVo.getModuleId();
    Long tenantId = moduleBuildVo.getTenantId();
    ModulePo modulePo = moduleService.get(moduleId, tenantId);
    BizException.doThrowIfNull("无法获取模块信息", modulePo);
    EnvPo envPo = envService.get(modulePo.getEnvId(), tenantId);
    BizException.doThrowIfNull("无法获取环境信息", envPo);
    JenkinsConfigPo jenkinsConfigPo = jenkinsConfigService.getByEnvId(modulePo.getEnvId(), modulePo.getTenantId());
    BizException.doThrowIfNull("缺少jenkins配置", jenkinsConfigPo);
    RegisterConfigPo registerConfigPo = registerConfigService
        .getByEnvId(modulePo.getEnvId(), modulePo.getTenantId());
    BizException.doThrowIfNull("缺少docker镜像配置", registerConfigPo);
    GitlabConfigPo gitlabConfigPo = gitlabConfigService
        .getByEnvId(modulePo.getEnvId(), modulePo.getTenantId());
    BizException.doThrowIfNull("缺少git配置", gitlabConfigPo);
    ProjectPo projectPo = projectService.get(modulePo.getProjectId(), tenantId);
    BizException.doThrowIfNull("无法获取项目信息", modulePo);
    ModuleResourcePo moduleResourcePo = moduleResourceService
        .listOne(new ModuleResourceQo().setModuleId(moduleId));
    moduleBuildVo.setProjectId(projectPo.getId());

    String commitId = gitWrapper.getLastCommitId(gitlabConfigPo, projectPo.getGitId(), moduleBuildVo.getBranch());
    commitId = commitId.substring(0, 7);

    jenkinsWrapper
        .build(jenkinsConfigPo, registerConfigPo, envPo.getNamespace(), projectPo, modulePo, moduleBuildVo, moduleResourcePo, commitId);
    moduleBuildVo.setResult(JenkinsBuildResultEnum.BUILDING.getDesc());

    // 之前构建的镜像相同名称记录标记已删除
    List<ModuleBuildPo> list = list(new ModuleBuildQo().setModuleId(moduleId).setImageName(moduleBuildVo.getImageName()));
    list.forEach(m->{
      m.setResult("已删除");
      update(m);
    });
    this.insert(moduleBuildVo);
    return moduleBuildVo;
  }

  @Override
  public BuildLogVo log(Long buildId, Integer bufferOffset, Long tenantId){
    ModuleBuildPo moduleBuildPo = this.get(buildId, tenantId);
    Long projectId = moduleBuildPo.getProjectId();
    ProjectPo projectPo = projectService.get(projectId, tenantId);
    BizException.doThrowIfNull("无法获取项目信息", projectPo);
    EnvPo envPo = envService.get(projectPo.getEnvId(), tenantId);
    BizException.doThrowIfNull("无法获取环境信息", envPo);
    JenkinsConfigPo jenkinsConfigPo = jenkinsConfigService.getByEnvId(projectPo.getEnvId(), projectPo.getTenantId());
    BizException.doThrowIfNull("缺少jenkins配置", jenkinsConfigPo);
    if(JenkinsBuildResultEnum.BUILDING.getDesc().equals(moduleBuildPo.getResult())){
      BuildLogVo buildLog = jenkinsWrapper
          .getBuildLog(jenkinsConfigPo, envPo.getNamespace(), projectPo.getName(), bufferOffset,
              moduleBuildPo.getBuildNum());
      if (null != buildLog && !buildLog.getHasMore() && !JenkinsBuildResultEnum.NULL.getDesc()
          .equals(buildLog.getResult())) {
        moduleBuildPo.setResult(buildLog.getResult());
        try {
          this.update(moduleBuildPo);
        } catch (Exception e) {
          log.warn("更新构建记录状态失败, {}", JSON.toJSONString(moduleBuildPo));
        }
      }
      return buildLog;
    }else {
      String allBuildLog = jenkinsWrapper
          .getAllBuildLog(jenkinsConfigPo, envPo.getNamespace(), projectPo.getName(), moduleBuildPo.getBuildNum());
      BuildLogVo buildLogVo = new BuildLogVo();
      buildLogVo.setLog(allBuildLog);
      buildLogVo.setHasMore(false);
      buildLogVo.setResult(moduleBuildPo.getResult());
      return buildLogVo;
    }
  }


  private ModuleBuildVo toVo(ModuleBuildPo po){
    ModuleBuildVo vo = po.convert(ModuleBuildVo.class);
    return vo;
  }

  private List<ModuleBuildVo> toVoList(List<ModuleBuildPo> list){
    if(CollectionUtils.isEmpty(list)){
      return Collections.emptyList();
    }

    return list.stream().map(po->{
      return toVo(po);
    }).collect(Collectors.toList());
  }

  @Override
  public ModuleBuildVo getVo(Long id, Long tenantId) {
    ModuleBuildPo po = this.get(id, tenantId);
    if(null == po){
      return null;
    }
    ModuleBuildVo vo = toVo(po);

    return vo;
  }

  @Override
  public List<ModuleBuildVo> listVo(ModuleBuildQueryVo q){
    ModuleBuildQo qo = q.convert(ModuleBuildQo.class);
    List<ModuleBuildPo> poList = this.list(qo);
    List<ModuleBuildVo> voList = toVoList(poList);

    return voList;
  }

  @Override
  public Result<List<ModuleBuildVo>> pageVo(ModuleBuildQueryVo param) {
    ModuleBuildQo qo = param.convert(ModuleBuildQo.class);
    int count = this.count(qo);
    if (0 == count) {
      return Result.successReturn(Collections.<ModuleBuildVo>emptyList()).setCount(count);
    }
    List<ModuleBuildPo> poList = this.list(qo);
    List<ModuleBuildVo> voList = toVoList(poList);

    return Result.successReturn(voList).setCount(count);
  }


}
